package gomz.pres;

import java.awt.Component;
import java.util.ArrayList;

import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

/**
 * Klasse fuer eine JList mit Checkboxen
 * @author Murillo
 */ 
public class CheckBoxList extends JList{
	private static final long serialVersionUID = 1L;
	private ArrayList<ListCheckedListener> listenerList = new ArrayList<ListCheckedListener>(); //Liste mit allen angmeldeten Listeners
	private boolean doDeselect = false;	//Boolean ob bei einem valueChanged event alle Element deselektiert wurden
	
	/**
	 * Konstruktor fuer eine Liste mit Checkboxen
	 * @param listData Array mit Strings, welche in der Liste angezeigt werden sollen.
	 */
	public CheckBoxList(String[] listData){
		//Listeninhalt in CheckBoxen umwandeln und an die Superklasse als ListData schicken
		super.setListData(stringArrToCheckBoxArr(listData));
		super.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		//Zelle mit folgendem Renderer zeichnen
		this.setCellRenderer(new CheckListRenderer());
		
		//Listener auf der List ob ein Element ausgewaehlt wurde
		this.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				//Sobald ein Element selektiert wurde und das event nicht vom deselektieren eines Elementes oder aller Element kommt,
				//soll die selektierte Checkbox von true auf false bzw. umgekehrt gesetzt werden.
				if (e.getValueIsAdjusting() == false && !doDeselect){
					CheckBoxList clb = (CheckBoxList)e.getSource();
					if(clb.getSelectedIndices().length > 0){
						//Checkbox status aendern
						JCheckBox cb = (JCheckBox)clb.getSelectedValue();
						if(cb.isSelected()) cb.setSelected(false);
						else				cb.setSelected(true);
						//Selektion wieder zuruecksetzten
						doDeselect = true;
						clb.clearSelection();
						//Angemeldete Listener benachrichtigen
						doNotify();
					}
				}
				//In folgenden fall wurde die Selektion auf 0 gesetzt
				else if(e.getValueIsAdjusting() == false && doDeselect){
					doDeselect= false;
				}
			}
		});
	}
	
	/**
	 * Diese Methode fuellt die uebergebenen Strings in die Liste
	 * @param listData Array mit Strings, welche in der Liste angezeigt werden sollen.
	 */
	public void setListData(String[] listData){
		//Ueberschreiben der vorhandenen Funktion und erstellen von Checkboxen aus den uebergebenen Strings
		super.setListData(stringArrToCheckBoxArr(listData));
	}
	
	/**
	 * Diese Methode benachrichtig alle angemeldeten Objekte
	 */
	private void doNotify(){
		for(ListCheckedListener listener: listenerList){
			listener.checkedPerformed();
		}
	}
	
	/**
	 * Diese Methode fueegt den Uebergeben Listener der Liste der zu informierenden Objekte hinzu.
	 * Sobald eine Checkbox selektiert oder deslektiert wird, werden alle Objekte in dieser Liste benachrichtigt
	 * @param listener Listener welcher benachricht werden soll.
	 */
	public void addListCheckedListener(ListCheckedListener listener){
		listenerList.add(listener);
	}
	
	/**
	 * Diese Methode deselektiert alle Checkboxen der Liste
	 */
	public void uncheckAll(){
		for(int i = 0; i < this.getModel().getSize(); i++){
			setUncheckedAtIndex(i);
		}
	}
	
	/**
	 * Diese Methode deselektiert die CheckBox am uebergebenen Index
	 * @param index Index der Checkbox, welche deselektiert werden soll
	 */
	public void setUncheckedAtIndex(int index){
		if(index >= 0 && index < this.getModel().getSize()){
			((JCheckBox)this.getModel().getElementAt(index)).setSelected(false);
			this.repaint();
		}
	}
	
	/**
	 * Diese Methode selektiert die Checkbox am uebergebenen index
	 * @param index Index der Checkbox, welche selektiert werden soll
	 */
	public void setCheckedIndex(int index){
		if(index >= 0 && index < this.getModel().getSize()){
			((JCheckBox)this.getModel().getElementAt(index)).setSelected(true);
			this.repaint();
		}
	}
	
	/**
	 * Diese Methode gibt die Indices der Checkboxen zurueck die checked sind.
	 * @return int[] Integerarray mit den Indeces der Checkboxen die checked sind.
	 */
	public int[] getCheckedIndeces(){
		//Indeces aller checked Checkboxen in ein ArrayList fuellen
		ArrayList<Integer> indices = new ArrayList<Integer>();
		for(int im = 0; im < this.getModel().getSize(); im++){
			if(((JCheckBox)this.getModel().getElementAt(im)).isSelected()) indices.add(im);
		}
		
		//ArrayList in einen Array umwandeln 
		int[] re = new int[indices.size()];
		for(int i = 0; i<re.length; i++){
			re[i] = indices.get(i);
		}
		return (re);
	}
	
	/**
	 * Diese Methode wandelt einen Stringarray in einen Array aus Checkboxen um.
	 * @param listData Stringarray der umgewadelt werden soll
	 * @return JCheckBox[] Checkboxarray mit den Texten der uebergebenen Strings
	 */
	private JCheckBox[] stringArrToCheckBoxArr (String[] listData){
		JCheckBox[] jArr = new JCheckBox[listData.length];
		//Checkboxen erstellen, deren Text dem uebergebenen String entspricht
		for (int i = 0; i < listData.length; i++){
			jArr[i] = new JCheckBox(listData[i]);
		}
		return (jArr);
	}
}

/**
 * Renderer fuer Checkboxen. Zeichnet Checkboxen in die Liste mit dem Inhalt der Checkboxen in der ListData
 * @author Murillo
 */ 
class CheckListRenderer extends JCheckBox implements ListCellRenderer {
	private static final long serialVersionUID = 1L;
	
	//Methode die das in die Liste zu zeichnende Element zurueck gibt.
	public Component getListCellRendererComponent(JList arg0, Object arg1,
			int arg2, boolean arg3, boolean arg4) {

		//Hintergrundfarbe der Chekbox entfernen
		this.setBackground(null);
		//Text der Checkbox von derjenigen aus der ListData uebernehmen
		this.setText(((JCheckBox)arg1).getText());
		//Checked status der Checkboxe von derjenigen aus der ListData uebernehmen
		this.setSelected(((JCheckBox)arg1).isSelected());
		
		return (this);
	}  
  } 